﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Xml;

namespace Xinnos.Lca.Yacht.Analyzer.View
{
    internal class ComponentViewModel:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public ObservableCollection<ComponentRateViewModel> Rates { get; set; }
        private string mName = null;
        private ComponentRateViewModel mRate = null;
        public string Name
        {
            get { return mName; }
            set
            {
                mName = value;
                RaisePropertyChanged("Name");
            }
        }
        public ComponentRateViewModel Rate
        {
            get { return mRate; }
            set
            {
                mRate = value;
                RaisePropertyChanged("Rate");
            }
        }

        public ComponentViewModel()
        {
            if (null == Rates) Rates = new ObservableCollection<ComponentRateViewModel>();

            WorkBreakdownStructuresViewModel _structures = WorkBreakdownStructuresViewModel.GetInstance();
            ConfigurationViewModel _configuration = ConfigurationViewModel.GetInstance();
            List<List<WorkBreakdownStructureViewModel>> _layers = new List<List<WorkBreakdownStructureViewModel>>();
            foreach (WorkBreakdownStructureGroupViewModel _group in _structures.Groups)
            {
                if (_configuration.Object != _group.Name)
                {
                    List<WorkBreakdownStructureViewModel> _selecteds = GetSelecteds(_group.WorkBreakdownStructures);
                    if (null != _selecteds) _layers.Add(_selecteds);
                }
            }
            List<List<WorkBreakdownStructureViewModel>> _lists = GetSequence(_layers, 0);
            if (null != _lists)
            {
                EnvironmentalProfilesViewModel _profiles = EnvironmentalProfilesViewModel.GetInstance();
                foreach (List<WorkBreakdownStructureViewModel> _list in _lists)
                {
                    ComponentRateViewModel _rate = new ComponentRateViewModel();
                    foreach (WorkBreakdownStructureViewModel _structure in _list) _rate.Sequences.Add(_structure);
                    for (int i = 0; i < _profiles.Profiles.Count; i++) _rate.Factors.Add(0.0);
                    Rates.Add(_rate);
                }
            }
        }

        private List<List<WorkBreakdownStructureViewModel>> GetSequence(IEnumerable<List<WorkBreakdownStructureViewModel>> enumerable,int nIndex)
        {
            List<List<WorkBreakdownStructureViewModel>> _list = null;
            if (null == enumerable) return _list;
            if (enumerable.Count<List<WorkBreakdownStructureViewModel>>() > nIndex)
            {
                List<WorkBreakdownStructureViewModel> _currents = enumerable.ElementAt<List<WorkBreakdownStructureViewModel>>(nIndex);
                foreach (WorkBreakdownStructureViewModel _current in _currents)
                {
                    List<List<WorkBreakdownStructureViewModel>> _nexts = GetSequence(enumerable, nIndex + 1);
                    if (null == _list) _list = new List<List<WorkBreakdownStructureViewModel>>();
                    if (null == _nexts)
                    {
                        List<WorkBreakdownStructureViewModel> _row = new List<WorkBreakdownStructureViewModel>();
                        _row.Add(_current);
                        _list.Add(_row);
                    }
                    else
                    {
                        foreach (List<WorkBreakdownStructureViewModel> _next in _nexts)
                        {
                            List<WorkBreakdownStructureViewModel> _row = new List<WorkBreakdownStructureViewModel>();
                            _row.Add(_current);
                            _row.AddRange(_next);
                            _list.Add(_row);
                        }
                    }
                }
            }
            return _list;
        }

        /// <summary>
        /// 선택한 WBS 요소 목록을 반환한다.
        /// 하위 요소 중에 선택한 것이 있는 경우 하위 요소만 반환한다.
        /// </summary>
        /// <param name="enumerable">WBS 목록</param>
        /// <returns>선택한 WBS 요소 목록</returns>
        private List<WorkBreakdownStructureViewModel> GetSelecteds(IEnumerable<WorkBreakdownStructureViewModel> enumerable)
        {
            List<WorkBreakdownStructureViewModel> _selecteds = null;
            if (null == enumerable) return _selecteds;
            List<WorkBreakdownStructureViewModel> _currents = null;
            foreach (WorkBreakdownStructureViewModel _structure in enumerable)
            {
                if (0 < _structure.Children.Count)
                {
                    List<WorkBreakdownStructureViewModel> _children = GetSelecteds(_structure.Children);
                    if (null != _children)
                    {
                        if (null == _selecteds) _selecteds = new List<WorkBreakdownStructureViewModel>();
                        _selecteds.AddRange(_children);
                    }
                }
                if (null == _selecteds)
                {
                    // 선택한 요소만 반환하는 것이 현시점에서 불편하여 필요할 때까지 기능 봉인
                    // 최하위 요소만 가져오는 기능으로 대체
                    //if (true == _structure.Selected)
                    //{
                        if (null == _currents) _currents = new List<WorkBreakdownStructureViewModel>();
                        _currents.Add(_structure);
                    //}
                }
            }
            if (null == _selecteds) _selecteds = _currents;
            return _selecteds;
        }

        public XmlElement Export(XmlDocument doc)
        {
            XmlElement _element = null;
            if (null == doc) return _element;
            _element = doc.CreateElement("Component");
            XmlAttribute _name = doc.CreateAttribute("Name");
            _name.Value = this.Name;
            _element.Attributes.Append(_name);
            if (0 < this.Rates.Count)
            {
                XmlElement _rates = doc.CreateElement("Rates");
                foreach (ComponentRateViewModel _rate in Rates) _rates.AppendChild(_rate.Export(doc));
                _element.AppendChild(_rates);
            }
            return _element;
        }
        public void Import(XmlElement element)
        {
            this.Name = null;
            if (0 < Rates.Count) Rates.Clear();
            if (null == element) return;
            if ("Component" == element.Name)
            {
                this.Name = element.Attributes["Name"].Value;
                if (element.HasChildNodes)
                {
                    foreach (XmlElement _child in element.ChildNodes)
                    {
                        if ("Rates" == _child.Name)
                        {
                            if (_child.HasChildNodes)
                            {
                                foreach (XmlElement _node in _child.ChildNodes)
                                {
                                    ComponentRateViewModel _rate = new ComponentRateViewModel();
                                    _rate.Import(_node);
                                    Rates.Add(_rate);
                                }
                            }
                        }
                    }
                }
            }
            else throw new XmlException("Component 요소가 없습니다.");
        }

        private void RaisePropertyChanged(string strPropertyName)
        {
            PropertyChangedEventHandler _handler = this.PropertyChanged;
            if (null != _handler) _handler(this, new PropertyChangedEventArgs(strPropertyName));
        }
    }
}